#ifdef ENABLE_DB_JUDGE
#include "database_judge.h"
#include "../utility/ojData.h"
#include "../utility/fileio.h"
#include "../utility/jsonObject.h"
#include "../utility/defer.h"
#include "../utility/os.h"
#include "../utility/log.h"

#include <string>
#include <fstream>
using std::operator""s;
DatabaseParams databaseParams;

ProcessStatus create_mysql_connect(MYSQL* conn, std::string host, int port,
                                    std::string user, std::string passwd, std::string database,
                                    int options, int timeout)
{
    ProcessStatus ps;
    int res;
    mysql_init(conn);
    mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
    mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout);
    mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout);
    //"root":数据库管理员 "123":root密码 "test":数据库的名字
    if (mysql_real_connect(conn, host.c_str(), user.c_str(), passwd.c_str(), database.c_str(), port, NULL, options)) {
        // 关闭自动提交
        res = mysql_autocommit(conn, false);
        if (res) {
            ps.result = RE;
            ps.errorcode = res;
            ps.error = mysql_error(conn);
            return ps;
        }
        // cout << "connect success" << endl;
        res = mysql_set_character_set(conn, "utf8");
        if (res) {
            ps.result = RE;
            ps.errorcode = res;
            ps.error = mysql_error(conn);
            return ps;
        }
    } else {
        ps.result = RE;
        ps.errorcode = RE;
        ps.error = mysql_error(conn);
        return ps;
    }
    ps.result = RUN_OK;
    return ps;
}

int check_update_database(MYSQL* conn, std::string database, std::string sql_file)
{
    char check_tables[256];
    sprintf(check_tables, 
        "SELECT UNIX_TIMESTAMP(min(create_time)) FROM information_schema.tables WHERE table_schema = '%s'", database.c_str());
    auto json = run_sql_result(conn, "", check_tables);
    // 出错
    if (json->getType() == JSONINT) {
        return -1;
    }
    // 如果不存在该数据库或没有表
    if (json->asArray().size() == 0 || json->asArray()[0]->asArray()[0]->getType() == JSONNULLPTR) {
        return 2;
    }
    auto ftime = getLastUpdateTime(sql_file);
    Log::instance().getOutput() << json->asArray()[0]->asArray()[0]->getTypeStr() << std::endl;
    Log::instance().getOutput() << json->asArray()[0]->asArray()[0]->asInt() << std::endl;
    Log::instance().getOutput() << ftime << std::endl;
    // 如果表的创建时间小于文件最晚更新时间则需要更新数据库
    if (json->asArray()[0]->asArray()[0]->asInt() < ftime) {
        return 1;
    }
    return 0;
}

ProcessStatus create_database(MYSQL *conn,
                              std::pair<std::string, std::string> user, // 普通用户权限的账号密码
                              std::string host, std::string database, std::string sql_file)
{
    ProcessStatus ps;
    JsonObjectPtr json;
    char command[128];
    int res;

    // 删除数据库
    sprintf(command, "drop database if exists `%s`", database.c_str());
    json = run_sql_result(conn, "", command);
    if (json->asInt() != 0) {
        ps.result = RE;
        ps.errorcode = json->asInt();
        ps.error = mysql_error(conn);
        return ps;
    }

    // 创建一个新的数据库
    sprintf(command, 
            "create database if not exists `%s` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;",
            database.c_str());
    json = run_sql_result(conn, "", command);
    if (json->asInt() != 0) {
        ps.result = RE;
        ps.errorcode = json->asInt();
        ps.error = mysql_error(conn);
        return ps;
    }

    res = mysql_select_db(conn, database.c_str());
    if (res) {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = mysql_error(conn);
        return ps;
    }

    std::ifstream if_sql_file(sql_file, std::ios::in | std::ios::ate);
    auto sql_file_size = if_sql_file.tellg();
    if_sql_file.seekg(0);
    Log::instance().getOutput() << "create sql :" << sql_file << std::endl;
    Log::instance().getOutput() << "create sql size:" << sql_file_size << std::endl;
    std::string sql_file_str(sql_file_size, '\0'); // construct string to stream size
    if_sql_file.seekg(0);
    if (!if_sql_file.read(&sql_file_str[0], sql_file_size)) {
        ps.result = SYS_ERROR;
        ps.error = "sql_file read error";
        return ps;
    }

    Log::instance().getOutput() << "create sql content:" << sql_file_str << std::endl;
    {
        mysql_set_server_option(conn, MYSQL_OPTION_MULTI_STATEMENTS_ON);
        defer(
            mysql_set_server_option(conn, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
        );
        res = mysql_query(conn, sql_file_str.c_str());
        if (res) {
            ps.result = MYSQL_ERROR;
            ps.error = "execute create database sql error:"s + mysql_error(conn);
            return ps;
        }
    }

    res = 0;
    while (res == 0) {
        /* did current statement return data? */
        auto result = mysql_store_result(conn);
        defer(
            mysql_free_result(result);
        );
        if (result) {
            /* yes; process rows and free the result set */
        } else /* no result set or error */ {
            if (mysql_field_count(conn) == 0) {
            } else  /* some error occurred */ {
                Log::instance().getError() << "no query statement, and occur error" << std::endl;
                ps.result = MYSQL_ERROR;
                ps.error = "create database error:"s + mysql_error(conn);
                return ps;
            }
        }
        /* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
        res = mysql_next_result(conn);
        if (res > 0) {
                Log::instance().getError() << "require next result, and occur error" << std::endl;
                ps.result = MYSQL_ERROR;
                ps.error = "create database error:"s + mysql_error(conn);
                return ps;
        }
    }

    // 查询所有的表名
    json = run_sql_result(conn, "", "show tables;");
    // 执行出现错误时
    if (json->getType() == JSONINT) {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = mysql_error(conn);
        return ps;
    // 正常情况下遍历表名,并删除所有数据
    } if (json->getType() == JSONARRAY) {
        const auto& tables = json->asArray();
        Log::instance().getOutput() << "tables:[" << json->json() << "]" << std::endl;
        for (int i = 0; i < tables.size();i ++) {
            char sql[SQL_MAX_SIZE];
            int index = 0;
            std::string table;
            try {
                table = tables[i]->asArray()[0]->asString();
            } catch (const char * e) {
                ps.result = RE;
                ps.error = e;
                return ps;
            }
            index += snprintf(sql + index, SQL_MAX_SIZE - index, "DELETE FROM `");
            index += mysql_real_escape_string_quote(conn, sql + index, table.c_str(), std::min((int)table.size(), SQL_MAX_SIZE - index), '\'');
            index += snprintf(sql + index, SQL_MAX_SIZE - index, "`");
            Log::instance().getOutput() << "index:[" << index << "],delete sql[" << sql << "]" << std::endl;
            auto delete_json = run_sql_result(conn, "", sql);
            Log::instance().getOutput() << "delete result:[" << delete_json->json() << "]" << std::endl;
            if (delete_json->getType() != JSONINT || delete_json->asInt() != 0) {
                ps.result = RE;
                ps.errorcode = delete_json->asInt();
                ps.error = mysql_error(conn);
                return ps;
            }
        }
    } else {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = "UNKOWN sql_result";
    }

    sprintf(command, 
            "GRANT select,update,insert,delete ON `%s`.* TO \"%s\"@\"%%\"  IDENTIFIED BY \"%s\"",
            database.c_str(), user.first.c_str(), user.second.c_str());
    Log::instance().getOutput() << command << std::endl; 
    json = run_sql_result(conn, database, std::string(command));
    if (json->asInt() != 0) {
        ps.result = RE;
        ps.errorcode = json->asInt();
        ps.error = mysql_error(conn);
        return ps;
    }
    ps.result = RUN_OK;
    return ps;
}

ProcessStatus drop_database(MYSQL *conn, const std::string& database) {
    // 删除数据库
    char command[128] = {0};
    sprintf(command, "drop database if exists `%s`", database.c_str());
    auto json = run_sql_result(conn, "", command);
    if (json->asInt() != 0) {
        ProcessStatus { .result = RE,
                        .errorcode = json->asInt(),
                        .error = mysql_error(conn),
        };
    }
    return ProcessStatus {.result = RUN_OK};
}

// 选择数据库
ProcessStatus select_database(MYSQL* conn, std::string database)
{
    ProcessStatus ps;
    int res = 0;
    if (database != "") {
        res = mysql_select_db(conn, database.c_str());
        if (res) {
            ps.result = RE;
            ps.errorcode = res;
            ps.error = mysql_error(conn);
        }
    }
    ps.result = RUN_OK;
    return ps;
}


ProcessStatus run_single_select_sql(MYSQL* conn, std::string database, const std::string& sql, unsigned int timeLimit)
{
    ProcessStatus ps;
    MYSQL_RES* result;
    MYSQL_FIELD* fields;
    int res = 0;

    ps = select_database(conn, database);
    if (ps.result != RUN_OK) {
        return ps;
    }

    // 启用profiling
    res = mysql_query(conn, "set profiling = on");
    if (res) {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = mysql_error(conn);
        return ps;
    }

    unsigned int old_read_timeout = 0;
    unsigned int old_write_timeout = 0;

    if (timeLimit > 0) {
        mysql_get_option(conn, MYSQL_OPT_READ_TIMEOUT, &old_read_timeout);
        mysql_get_option(conn, MYSQL_OPT_WRITE_TIMEOUT, &old_write_timeout);
        mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeLimit);
        mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeLimit);
    }

    res = mysql_query(conn, sql.c_str());

    if (timeLimit > 0) {
        mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &old_read_timeout);
        mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &old_write_timeout);
    }

    Log::instance().getOutput() << sql << std::endl;
    if (res) {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = mysql_error(conn);
        return ps;
    } else {
        if (result = mysql_store_result(conn)) {
            int col_num = mysql_num_fields(result);
            int row_num = mysql_num_rows(result);
            fields = mysql_fetch_fields(result);
            // Log::instance().printf("row_num:%d,col_num:%d\n", row_num, col_num);
            // for (int i = 0;i < col_num;i++) {
            //     cout << fields[i].name << "(" << fields[i].type << ")" << "##";
            // }

            // 存入查询结果
            ps.extern_info = mysql_dump_result(result);
            mysql_free_result(result);
            // 存入表头信息
            ps.extern_info->asArray().insert(ps.extern_info->asArray().begin(), JSONOBJECT(JsonArray()));
            JsonArray& array = ps.extern_info->asArray()[0]->asArray();
            for (int i = 0;i < col_num; i++) 
            {
                array.push_back(JSONOBJECT(fields[i].name));
            }
            // 获得当前sql的运行信息
            auto resource = get_last_statement_resource(conn);
            ps.time = resource.first;
            ps.memory = resource.second;
            ps.result = RUN_OK;
        } else {
            if(mysql_field_count(conn) == 0) {
                // query does not return data
                // (it was not a SELECT)
                Log::instance().printf("empty table\n");
                ps.result = RE;
                ps.error = "it was not a SELECT";
            } else { // mysql_store_result() should have returned data
                ps.result = RE;
                ps.errorcode = res;
                ps.error = mysql_error(conn);
            }
        }
    }
    return ps;
}

ProcessStatus run_single_modify_sql(MYSQL* conn, std::string database, const std::string& sql, unsigned int timeLimit)
{
    ProcessStatus ps;
    int res;
    ps = select_database(conn, database);
    if (ps.result != RUN_OK) {
        return ps;
    }

    // 启用profiling
    res = mysql_query(conn, "set profiling = on");
    if (res) {
        ps.result = RE;
        ps.errorcode = res;
        ps.error = mysql_error(conn);
    }

    unsigned int old_read_timeout = 0;
    unsigned int old_write_timeout = 0;

    if (timeLimit > 0) {
        mysql_get_option(conn, MYSQL_OPT_READ_TIMEOUT, &old_read_timeout);
        mysql_get_option(conn, MYSQL_OPT_WRITE_TIMEOUT, &old_write_timeout);
        mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeLimit);
        mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeLimit);
    }

    // 执行完当前sql命令后进行全数据库查询
    // 因为不知道确切更新的数据表,以及是否有额外的影响
    auto json = run_sql_result(conn, database, sql);
    if (json->getType() != JSONINT) {
        ps.result = RE;
        ps.error = "it was not as insert/update/delete";
        Log::instance().getError() << "current sql:[" << sql << "]" << std::endl;
        return ps;
    }
    if (json->asInt() != 0) {
        ps.result = RE;
        ps.errorcode = json->asInt();
        ps.error = mysql_error(conn);
        return ps;
    }
    Log::instance().getOutput() << "modify json:" << json->json() << std::endl;

    if (timeLimit > 0) {
        mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &old_read_timeout);
        mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &old_write_timeout);
    }

    // 获取该sql的时间内存
    auto resource = get_last_statement_resource(conn);
    ps.time = resource.first;
    ps.memory = resource.second;

    // 执行全数据库表扫描
    std::string select_tables_sql = "show tables";
    auto tables = run_sql_result(conn, database, select_tables_sql);
    Log::instance().getOutput() << "tables:" << tables->json() << std::endl;
    // 返回错误
    if (tables->getType() == JSONINT) {
        ps.result = SPJFILE_RUN_ERROR;
        ps.errorcode = tables->asInt();
        ps.error = mysql_error(conn);
        return ps;
    }
    JsonArray& table_names = tables->asArray();
    // 没有搜索到表
    if (table_names.size() == 0) {
        ps.result = LESS_STDFILES;
        return ps;
    }
    // 遍历表,存储到ps结果中
    ps.extern_info = JSONOBJECT(JsonDict());
    JsonDict& dict = ps.extern_info->asDict();
    char select_sql[SQL_MAX_SIZE];
    int index = 0;
    for (JsonObjectPtr table : table_names)
    {
        std::string& table_name = table->asArray()[0]->asString();
        index = 0;
        index += snprintf(select_sql + index, SQL_MAX_SIZE - index, "SELECT * FROM `");
        index += mysql_real_escape_string_quote(conn, select_sql + index, table_name.c_str(), std::min((int)table_name.size(), SQL_MAX_SIZE - index), '\'');
        index += snprintf(select_sql + index, SQL_MAX_SIZE - index, "`");
        // 之前已经选择过database了,可忽略
        dict[table_name] = run_sql_result(conn, "", select_sql);
    }
    return ps;
}

JsonObjectPtr mysql_dump_result(MYSQL_RES* result)
{
    MYSQL_FIELD* fields;
    unsigned long* lens;
    MYSQL_ROW row;
    int col_num = mysql_num_fields(result);
    int row_num = mysql_num_rows(result);
    fields = mysql_fetch_fields(result);
    Log::instance().printf("row_num:%d,col_num:%d\n", row_num, col_num);
    for (int i = 0;i < col_num;i++) {
        Log::instance().getOutput() << fields[i].name << "(" << fields[i].type << ")" << "##";
    }
    Log::instance().getOutput() << std::endl;
    JsonObjectPtr res_json = JSONOBJECT(JsonArray());
    if (result == NULL) {
        Log::instance().getOutput() << "empty result" << std::endl;
        return res_json;
    }
    while (row = mysql_fetch_row(result))
    {
        lens = mysql_fetch_lengths(result);
        res_json->asArray().push_back(JSONOBJECT(JsonArray()));
        JsonArray &now_row = res_json->asArray().back()->asArray();
        for (int i = 0; i < col_num; i++)
        {
            now_row.push_back(mysql_value_to_jsonobj(fields[i], row[i], lens[i]));
        }
    }
    Log::instance().getOutput() << "parse ok" << std::endl;
    Log::instance().getOutput() << "test:" << res_json->json() << std::endl;
    return res_json;
}

std::pair<int, int> get_last_statement_resource(MYSQL *conn)
{
    std::string sql = "SELECT SUM(DURATION), SUM(BLOCK_OPS_IN) + SUM(BLOCK_OPS_OUT) "
                        " FROM INFORMATION_SCHEMA.PROFILING "
                        " WHERE QUERY_ID = (SELECT MAX(QUERY_ID) FROM INFORMATION_SCHEMA.PROFILING);";
    auto result = run_sql_result(conn, "", sql);
    Log::instance().getOutput() << "show profile:" << result->json() << std::endl;
    if (result->getType() != JSONARRAY) {
        Log::instance().getOutput() << "profile error:" << mysql_error(conn) << std::endl;
        return {-1, -1};
    }
    JsonArray& array = result->asArray();
    if (array.size() > 0) {
        array = array[0]->asArray();
        Log::instance().getOutput() << array[0]->getTypeStr() << " " << array[1]->getTypeStr() << std::endl;
        std::pair<int,int> result_p = {-1, -1};
        if (array[0]->getType() != JSONNULLPTR) {
            result_p.first = array[0]->getDouble() * 1000;
        }
        if (array[1]->getType() != JSONNULLPTR) {
            result_p.second = array[1]->getInt();
        }
        return result_p;
    }
    return {-1, -1};
}

JsonObjectPtr mysql_value_to_jsonobj(MYSQL_FIELD field, const char* value, int len)
{
    Log::instance().printf("val_to_jsonobj:type[%d],val[%s],len[%d]\n", field.type, value, len);
    // NULL返回null
    if (len == 0 && value == (void*)0) {
        return JSONOBJECT(nullptr);
    }
    switch (field.type)
    {
    case MYSQL_TYPE_NULL:
        return JSONOBJECT(nullptr);
        break;
    case MYSQL_TYPE_TINY:
    case MYSQL_TYPE_SHORT:
    case MYSQL_TYPE_LONG:
    case MYSQL_TYPE_INT24:
    case MYSQL_TYPE_LONGLONG:
    case MYSQL_TYPE_TIMESTAMP:
        return JSONOBJECT(strtoll(value, NULL, 0));
        break;
    case MYSQL_TYPE_DECIMAL:
    case MYSQL_TYPE_NEWDECIMAL:
    case MYSQL_TYPE_FLOAT:
    case MYSQL_TYPE_DOUBLE:
        return JSONOBJECT(strtod(value, NULL));
        break;

    // 其余一律按字符串处理
    default:
        // 二进制数据按照小写十六进制字符存储
        if (field.flags & BINARY_FLAG) {
            return JSONOBJECT(encodeHexString(value, len));
        } else {
            return JSONOBJECT(value);
        }
        break;
    }
}

ProcessStatus write_example(MYSQL* conn, std::string database, const std::string& data)
{
    int ret;
    ProcessStatus res;
    MYSQL_RES* result;
    Log::instance().getOutput() << "database name:" << database << std::endl;
    if (database != "") {
        ret = mysql_select_db(conn, database.c_str());
        if (ret) {
            res.result = RE;
            res.error = mysql_error(conn);
            return res;
        }
    }
    // 解析json
    auto dict = JsonObject::decoder(data);
    if (dict->getType() != JSONDICT)
    {
        res.result = RE;
        res.error = "std example can't Deserialization";
        Log::instance().getOutput() << "dict type:" << dict->getTypeStr() << std::endl;
        return res;
    }
    Log::instance().getOutput() << "data[" << std::endl
                                << dict->json() << std::endl
                                << "]" << std::endl;
    for (auto p : dict->asDict())
    {
        const std::string& table = p.first;
        if (p.second->getType() != JSONARRAY) {
            res.result = RE;
            res.error = "std example must be Dict[Str, List[List[BaseType]] ]";
            return res;
        }
        // 存储sql语句
        char sql[SQL_MAX_SIZE] = {0};
        // 存储sql执行结果
        JsonObjectPtr sql_result;

        const auto& arr = p.second->asArray();
        // 只有表头但是没有表数据,跳过这张表的数据插入
        if (arr.size() <= 1) {
            break;
        }
        if (arr[0]->getType() != JSONARRAY) {
            res.result = RE;
            res.error = "std example must be Dict[Str, List[List[Str | Number]] ]";
            return res;
        }
        int col_len = arr[0]->asArray().size();
        Log::instance().getOutput() << "col_len:" << col_len << std::endl;
        // 列数据为空也跳过
        if (col_len <= 0) {
            break;
        }
        for (auto header : arr[0]->asArray())
        {
            if (header->getType() != JSONSTRING) {
                res.result = RE;
                res.error = "table headers must be List[Str]";
                return res;
            }
        }


        // 检查列名是否存在
        // xxx
        const auto& headers = arr[0]->asArray();
        int index = 0;

        // 所有的错误将在执行插入语句时得到
        index = 0;
        index += snprintf(sql + index, SQL_MAX_SIZE - index, "insert into `");
        index += mysql_real_escape_string_quote(conn, sql + index, table.c_str(), std::min((int)table.size(), SQL_MAX_SIZE - index), '`');
        index += snprintf(sql + index, SQL_MAX_SIZE - index, "`(");
        for (int i = 0;i < col_len;i++)
        {
            if (i == 0) {
                index += snprintf(sql + index, SQL_MAX_SIZE - index, "`");
            } else {
                index += snprintf(sql + index, SQL_MAX_SIZE - index, ",`");
            }
            index += mysql_real_escape_string_quote(conn, sql + index, headers[i]->asString().c_str(), std::min((int)headers[i]->asString().size(), SQL_MAX_SIZE - index), '`');
            index += snprintf(sql + index, SQL_MAX_SIZE - index, "`");
            if (index >= SQL_MAX_SIZE) {
                res.result = RE;
                res.error = "columns name too long";
                return res;
            }
        }
        index += snprintf(sql + index, SQL_MAX_SIZE - index, ") values('");
        for (int i = 1;i < arr.size();i++)
        {
            if (arr[i]->getType() != JSONARRAY) {
                res.result = RE;
                res.error = "table row must be List[Str | Number]";
                return res;
            }
            // 每条数据逐行插入，使用转义
            const auto& row = arr[i]->asArray();
            if (row.size() != col_len) {
                res.result = RE;
                res.error = "header column count not equal data column count";
                return res;
            }
            int row_index = index;
            for (int j = 0;j < col_len;j++)
            {
                if (j > 0) {
                    row_index += snprintf(sql + row_index, SQL_MAX_SIZE - row_index, "','");
                    if (row_index >= SQL_MAX_SIZE) {
                        res.result = RE;
                        res.error = "sql statement too long";
                        return res;
                    }
                }
                auto& element = row[j];
                switch (element->getType()) {
                case JSONINT:
                    row_index += snprintf(sql + row_index, SQL_MAX_SIZE - row_index, "%lld", element->asInt());
                    break;
                case JSONSTRING:
                    row_index += mysql_real_escape_string_quote(conn, sql + row_index, element->asString().c_str(), std::min((int)element->asString().size(), SQL_MAX_SIZE - row_index), '\'');
                    break;
                case JSONDOUBLE:
                    row_index += snprintf(sql + row_index, SQL_MAX_SIZE - row_index, "%lf", element->asDouble());
                    break;
                default:
                    res.result = RE;
                    res.error = "element type must be string or number";
                    return res;
                    break;
                }
                if (row_index >= SQL_MAX_SIZE) {
                    res.result = RE;
                    res.error = "sql statement too long";
                    return res;
                }
            }
            row_index += snprintf(sql + row_index, SQL_MAX_SIZE - row_index, "')");
            if (row_index >= SQL_MAX_SIZE) {
                res.result = RE;
                res.error = "sql statement too long";
                return res;
            }
            Log::instance().getOutput() << "insert example sql[" << sql << "]" << std::endl;
            // 执行拼接好的语句
            sql_result = run_sql_result(conn, database, sql);
            Log::instance().getOutput() << "insert result [" << sql_result->json() << "]" << std::endl;
            if (sql_result->getType() != JSONINT || sql_result->asInt() != 0) {
                res.result = RE;
                res.error = "example insert sql statement run error";
                return res;
            }
        }
        
    }
    // 数据插入完毕,返回RUN_OK
    res.result = RUN_OK;
    return res;
}

JsonObjectPtr run_sql_result(MYSQL* conn, std::string database, const std::string& sql)
{
    int res;
    MYSQL_RES* result;
    if (database != "") {
        res = mysql_select_db(conn, database.c_str());
        if (res) {
            return JSONOBJECT(res);
        }
    }
    Log::instance().getOutput() << database << std::endl << sql << std::endl;
    res = mysql_query(conn, sql.c_str());
    if (res) {
        Log::instance().printf("error:%d\n", res);
        Log::instance().printf("Error: %s\n", mysql_error(conn));
        return JSONOBJECT(res);
    } else {
        if (result = mysql_store_result(conn)) {
            auto json = mysql_dump_result(result);
            Log::instance().getOutput() << "result_json:" << json->json() << std::endl;
            mysql_free_result(result);
            return json;
        } else {
            if(mysql_field_count(conn) == 0) {
                // query does not return data
                // (it was not a SELECT)
                Log::instance().printf("empty table\n");
                return JSONOBJECT(0);
            } else { // mysql_store_result() should have returned data
                Log::instance().printf("Error: %s\n", mysql_error(conn));
                return JSONOBJECT(res);
            }
        }
    }
    return JSONOBJECT(0);
}
#endif